package controllers;

import play.*;
import play.data.binding.As;
import play.data.validation.Email;
import play.data.validation.Required;
import play.data.validation.Validation.ValidationResult;
import play.exceptions.MailException;
import play.libs.Codec;
import play.libs.Crypto;
import play.libs.Mail;
import play.mvc.*;

import java.io.File;
import java.security.SecureRandom;
import java.util.*;

import javax.persistence.PersistenceException;
import javax.xml.bind.ValidationException;

import net.sf.oval.exception.ValidationFailedException;

import org.apache.commons.mail.SimpleEmail;
import org.junit.Ignore;

import models.*;
import models.livro.Livro;
import models.livro.LivroUsuario;
import models.usuario.Perfil;
import models.usuario.Usuario;

public class Application extends Controller {

    public static void index() {
    	if(Security.isConnected()){
    		Panel.index();
    	}
        render();
    }
    
    public static void registrar() {
    	render();
    }
    
    public static void recuperacaoSenha(){
    	render();
    }
    
    public static void listarLivros() {
    	List<Livro> livros = Livro.find("order by nome").fetch();
    	render(livros);
    }
    
    public static void listarUsuarios() {
    	List<Usuario> usuarios = Usuario.find("order by email").fetch();
    	render(usuarios);
    }
    
    public static void listarEmprestimos() {
    	List<Emprestimo> emprestimos = Emprestimo.findAll();
    	render(emprestimos);
    }
    
    //realiza uma pesquisa de usuarios
    public static void realizarPesquisaUsuario(String texto){
    	List<Usuario> usuarios = Usuario.find("email like ? order by email", "%"+texto+"%").fetch();
    	render(usuarios);
    }
    
    //realiza uma pesquisa de livros
    public static void realizarPesquisaLivro(String texto){
    	List<Livro> livros = Livro.find("nome like ? order by nome", "%"+texto+"%").fetch();
    	render(livros);
    }
    
    //Exibe detalhes de um livro
    public static void detalhesLivro(@Required String livroNome){
    	try{
    	Livro livro = Livro.find("byNome", livroNome).first();
    	List<Usuario> proprietarios = new ArrayList<Usuario>();
    	List<LivroUsuario> livros = LivroUsuario.findAll();
    	for (LivroUsuario l : livros) {
			if(l.livro.nome.equalsIgnoreCase(livroNome)){
				proprietarios.add(l.proprietario);
			}
		}
    	
    	render(livro,proprietarios);
    	}
    	catch(Exception ex){
    		
    	}
    }
    
    //conectar usuario
    public static Usuario conectar(String email, String senha){
    	try{
    	Usuario us = Usuario.find("byEmail", email).first();
    	if(senhaValida(senha, us.salt, us.senha)==true){
    		return us;
    	}
    	}catch(Exception ex){
    		
    	}
    	return null;

    }
    
    /**
     * Adiciona um novo usuário ao sistema.
     * @param email Email a ser utilizado pelo usuário.
     * @param senha Senha do usuário, a ser criptografada.
     */
    public static void criarUsuario(@Required @Email String email, @Required String senha,@Required String nome,
    		@Required String sobrenome,String telefone,String celular){
    	flash.put("url", "/application/registrar");
    	//verfica se o usuário já existe
    	Usuario us = Usuario.find("byEmail", email).first();
    	if(us!=null){
    	  	flash.keep("url");
        	flash.error("registrar.errorExistente");
        	params.flash();
        	registrar();
    	}
    	//verifica se há erros nos campos de preenchimento
    	else if(validation.hasErrors()){
    		flash.keep("url");
    		flash.error("registrar.errorCampos");
    		params.flash();
    		registrar();
    	}
    	
    	Perfil perfil=  new Perfil(nome, sobrenome, telefone, celular).save(); 	
    	Usuario usuario = new Usuario(email, senha,perfil);
    	usuario.save();
    	flash.keep("url");
    	flash.success("registrarusuario.success");
    	params.flash();
    	registrar();
    }
    
    /**
     * Checa se a senha passada pelo usuário é verdadeira.
     * @param senha Senha passada pelo usuário.
     * @param salt Salt armazenado no banco.
     * @param senhaBD Senha criptografada armazenada no banco.
     * @return Veracidade da senha.
     */
    public static boolean senhaValida(String senha, String salt, String senhaBD){
    	return (encriptaSenha(senha, salt).equals(senhaBD));
    }
    
    /**
     * Codifica a senha do usuário utilizando o padrão determinado.
     * @param senha Senha passada pelo usuário.
     * @param salt Salt armazenado no banco;
     * @return Senha criptografada.
     */
    public static String encriptaSenha(String senha, String salt){
    	return Crypto.passwordHash((salt.concat(senha)), Crypto.HashType.SHA256);
    }
    
    /**
     * Envia uma nova senha ao usuário de acordo com o email fornecido
     * **/
    public static void recuperarSenha(@Required @Email String emailUsuario){
    	try{
    	flash.put("url", "/application/recuperacaosenha");
    	Usuario usuario = Usuario.find("byEmail", emailUsuario).first();
    	if(usuario==null){
    		flash.keep("url");
        	flash.error("recuperar.error");
        	params.flash();
        	recuperacaoSenha();
    	}
    	
    	else if(validation.hasErrors()){
    		flash.keep("url");
    		flash.error("registrar.errorCampos");
    		params.flash();
    		recuperacaoSenha();
    	}
    	
    	SecureRandom rand = new SecureRandom();
		long num = rand.nextLong();
		usuario.salt = Codec.encodeBASE64(String.valueOf(num));
    	
		String[] carct ={"0","1","2","3","4","5","6","7","8","9",
				"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z",
				"A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"}; 

		String senha=""; 


		for (int x=0; x<6; x++){ 
		int j = (int) (Math.random()*carct.length); 
		senha += carct[j]; 

		} 
		
		usuario.senha = encriptaSenha(senha, usuario.salt);
		SimpleEmail email = new SimpleEmail();
		email.addTo(emailUsuario);
		email.setFrom("cabeceira_ca_livros@gmail.com", "CAbeceira");
		email.setSubject("CAbeceira-Empréstimo de Livros - Recuperação de senha");
		email.setMsg("Sua Nova senha é: "+senha);
		email.setCharset("UTF-8");
		Mail.send(email);
		usuario.save();
		flash.keep("url");
    	flash.success("recuperar.success");
    	params.flash();
    	recuperacaoSenha();
		}
		catch (MailException e) {
			error(e);
		}
    	catch (Exception e) {
			error(e);
		}
		
    }
    
    /**
     * Renderiza uma capa de livro forncecendo o nome de um livro
     * **/
    public static void getCapa(String livroNome) {
    	 Livro livro = Livro.find("byNome", livroNome).first();
         if(livro.capa.get()==null){
         	File f= Play.getFile("/public/images/sem-imagem.jpg");
         	renderBinary(f);
         }
         response.setContentTypeIfNotSet(livro.capa.type());
         renderBinary(livro.capa.get());
    }
}